

package android.graphics;

/**
 * The NinePatch class permits（许可） drawing a bitmap in nine or more sections（阶段）.
 * Essentially（本质上）, it allows the creation of custom（自定义） graphics（图形） that will scale the way that you define,
 * when content added within the image exceeds（超过） the normal bounds of the graphic.
 * For a thorough（深入） explanation（说明） of a NinePatch image,
 * read the discussion（讨论） in the
 * <a href="{@docRoot}guide/topics/graphics/2d-graphics.html#nine-patch">2D
 * Graphics</a> document.
 * <p>
 * The <a href="{@docRoot}guide/developing/tools/draw9patch.html">Draw 9-Patch</a> 
 * tool offers an extremely（及其） handy（方便） way to create your NinePatch images,
 * using a WYSIWYG graphics editor.
 * </p>
 */

public class NinePatch {
    /**
     * Struct （结构）of inset（插入） information attached （附加）to a 9 patch bitmap.
     *
     * Present on a 9 patch bitmap if it optical（视觉上） insets were manually（手动） included,
     * or if outline(轮廓) insets were automatically included by aapt.
     *如果手动包含光学插入，或者如果轮廓插入由aapt自动包含，则在9位补丁位图上显示。
     * @hide
     */
    public static class InsetStruct {
        //optical:光学。视觉上
        public final Rect opticalRect;
        public final Rect outlineRect;
        public final float outlineRadius;
        public final float outlineAlpha;

        @SuppressWarnings({"UnusedDeclaration"}) // called from JNI
            //optical:视觉上
          //decode:解码
        InsetStruct(int opticalLeft, int opticalTop, int opticalRight, int opticalBottom,
                int outlineLeft, int outlineTop, int outlineRight, int outlineBottom,
                float outlineRadius, int outlineAlpha, float decodeScale) {
            opticalRect = new Rect(opticalLeft, opticalTop, opticalRight, opticalBottom);
            outlineRect = new Rect(outlineLeft, outlineTop, outlineRight, outlineBottom);

            if (decodeScale != 1.0f) {
                // if bitmap was scaled when decoded, scale the insets from the metadata values
                opticalRect.scale(decodeScale);

                // round inward while scaling outline, as the outline should always be conservative
                outlineRect.scaleRoundIn(decodeScale);
            }
            this.outlineRadius = outlineRadius * decodeScale;
            this.outlineAlpha = outlineAlpha / 255.0f;
        }


    }

    private final Bitmap mBitmap;

    /**
     * Used by native code. This pointer is an instance of Res_png_9patch*.
     *
     * @hide
     */
    public final long mNativeChunk;

    private Paint mPaint;
    private String mSrcName;

    /**
     * Create a drawable projection （映射）from a bitmap to nine patches.
     *
     * @param bitmap The bitmap describing the patches.
     * @param chunk The 9-patch data chunk（块） describing how the underlying bitmap
     *              is split apart and drawn.
     *              描述底层位图如何拆分和绘制的9块数据块（块）。
     */
    public NinePatch(Bitmap bitmap, byte[] chunk) {
        this(bitmap, chunk, null);
    }

    /** 
     * Create a drawable projection from a bitmap to nine patches.
     *
     * @param bitmap The bitmap describing the patches.
     * @param chunk The 9-patch data chunk describing how the underlying
     *              bitmap is split apart and drawn.
     * @param srcName The name of the source for the bitmap. Might be null.
     */
    public NinePatch(Bitmap bitmap, byte[] chunk, String srcName) {
        mBitmap = bitmap;
        mSrcName = srcName;
        mNativeChunk = validateNinePatchChunk(mBitmap.ni(), chunk);
    }

    /**
     * @hide
     */
    public NinePatch(NinePatch patch) {
        mBitmap = patch.mBitmap;
        mSrcName = patch.mSrcName;
        if (patch.mPaint != null) {
            mPaint = new Paint(patch.mPaint);
        }
        // No need to validate（验证） the 9patch chunk again, it was done by the instance we're copying from
        //没有必要再次验证9patch块，它是由我们复制的实例完成的
        mNativeChunk = patch.mNativeChunk;
    }

    @Override
    protected void finalize() throws Throwable {
        try {
            if (mNativeChunk != 0) {
                // only attempt to destroy correctly initilized chunks
                //只试图正确地销毁已初始化的块
                nativeFinalize(mNativeChunk);
            }
        } finally {
            super.finalize();
        }
    }

    /**
     * Returns the name of this NinePatch object if one was specified when calling the constructor.
     */
    public String getName() {
        return mSrcName;
    }

    /**
     * Returns the paint used to draw this NinePatch. The paint can be null.
     *
     * @see #setPaint(Paint)
     * @see #draw(Canvas, Rect)
     * @see #draw(Canvas, RectF)
     */
    public Paint getPaint() {
        return mPaint;
    }

    /**
     * Sets the paint to use when drawing the NinePatch.
     *
     * @param p The paint that will be used to draw this NinePatch.
     *
     * @see #getPaint()
     * @see #draw(Canvas, Rect)
     * @see #draw(Canvas, RectF)
     */
    public void setPaint(Paint p) {
        mPaint = p;
    }

    /**
     * Returns the bitmap used to draw this NinePatch.
     */
    public Bitmap getBitmap() {
        return mBitmap;
    }
    
    /** 
     * Draws the NinePatch. This method will use the paint returned by {@link #getPaint()}.
     *
     * @param canvas A container for the current matrix and clip used to draw the NinePatch.
     * @param location Where to draw the NinePatch.
     */
    public void draw(Canvas canvas, RectF location) {
        canvas.drawPatch(this, location, mPaint);
    }

    /** 
     * Draws the NinePatch. This method will use the paint returned by {@link #getPaint()}.
     *
     * @param canvas A container for the current matrix and clip used to draw the NinePatch.
     * @param location Where to draw the NinePatch.
     */
    public void draw(Canvas canvas, Rect location) {
        canvas.drawPatch(this, location, mPaint);
    }

    /** 
     * Draws the NinePatch. This method will ignore the paint returned
     * by {@link #getPaint()} and use the specified paint instead.
     *
     * @param canvas A container for the current matrix and clip used to draw the NinePatch.
     * @param location Where to draw the NinePatch.
     * @param paint The Paint to draw through.
     */
    public void draw(Canvas canvas, Rect location, Paint paint) {
        canvas.drawPatch(this, location, paint);
    }

    void drawSoftware(Canvas canvas, RectF location, Paint paint) {
        nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.ni(), mNativeChunk,
                paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity);
    }

    void drawSoftware(Canvas canvas, Rect location, Paint paint) {
        nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.ni(), mNativeChunk,
                paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity);
    }

    /**
     * Return the underlying bitmap's density, as per {@link Bitmap#getDensity() Bitmap.getDensity()}.
     * 根据Bitmap＃getDensity（）Bitmap.getDensity（）}返回底层位图的密度。
     */
    public int getDensity() {
        return mBitmap.mDensity;
    }

    /**
     * Returns the intrinsic width, in pixels, of this NinePatch.
     * This is equivalent to querying the width of the underlying bitmap returned by {@link #getBitmap()}.
     * 返回此NinePatch的内部宽度（以像素为单位）。
     * 这相当于查询{@link #getBitmap（）}返回的底层位图的宽度。
     */
    public int getWidth() {
        return mBitmap.getWidth();
    }

    /**
     * Returns the intrinsic height, in pixels, of this NinePatch.
     * This is equivalent to querying the height of the underlying bitmap returned by {@link #getBitmap()}.
     * 返回此NinePatch的固有高度（以像素为单位）。
           *这相当于查询{@link #getBitmap（）}返回的底层位图的高度。
     */
    public int getHeight() {
        return mBitmap.getHeight();
    }

    /**
     * Indicates whether this NinePatch contains transparent or translucent pixels.
     * This is equivalent to calling <code>getBitmap().hasAlpha()</code> on this NinePatch.
     * *表示NinePatch是否包含透明或半透明像素。
           *这相当于在NinePatch上调用<code> getBitmap（）。hasAlpha（）</ code>。
     */
    public final boolean hasAlpha() {
        return mBitmap.hasAlpha();
    }

    /**
     * Returns a {@link Region} representing the parts of the NinePatch that are  completely transparent.
     *返回表示NinePatch中完全透明的部分的{@link Region}。
     * @param bounds The location and size of the NinePatch.
     *               NinePatch的位置和大小。
     *
     * @return null if the NinePatch has no transparent region to report,
     * else a {@link Region} holding the parts of the specified bounds that are transparent.
     *
     * ull如果NinePatch没有透明区域进行报告，
          *否则保持指定边界的透明部分。
     */
    public final Region getTransparentRegion(Rect bounds) {
        long r = nativeGetTransparentRegion(mBitmap.ni(), mNativeChunk, bounds);
        return r != 0 ? new Region(r) : null;
    }

    /**
     * Verifies that the specified byte array is a valid 9-patch data chunk.
     * 验证指定的字节数组是否是有效的9补丁数据块。
     *
     * @param chunk A byte array representing a 9-patch data chunk.
     *
     * @return True if the specified byte array represents a 9-patch data chunk,
     *         false otherwise.
     */
    public native static boolean isNinePatchChunk(byte[] chunk);

    /**
     * Validates the 9-patch chunk and throws an exception if the chunk is invalid.
     * If validation is successful, this method returns a native Res_png_9patch object used by the renderers.
     * 验证9补丁块并在块无效时抛出异常。
           *如果验证成功，则此方法返回呈示器使用的本机Res_png_9patch对象。
     */
    private static native long validateNinePatchChunk(long bitmap, byte[] chunk);
    private static native void nativeFinalize(long chunk);
    private static native void nativeDraw(long canvas_instance, RectF loc, long bitmap_instance,
            long c, long paint_instance_or_null, int destDensity, int srcDensity);
    private static native void nativeDraw(long canvas_instance, Rect loc, long bitmap_instance,
            long c, long paint_instance_or_null, int destDensity, int srcDensity);
    private static native long nativeGetTransparentRegion(long bitmap, long chunk, Rect location);
}
